// 游戏界面的js

// 玩家界面
let playerDivs = [];
// 庄家界面
let bankerBox = document.querySelector(".banker-box");

// 存储玩家数据信息
let players = [];
// 存储庄家信息
let banker = { win: 0, lose: 0, cards: [] };

// 当前玩家
let playerIndex = 0;

// 游戏环节
let procedure = ['切牌', '押注', "要牌"];
// 游戏环节步骤
let procedureIndex = -1;


// 根据游戏玩家数量，初始化玩家界面
function initPlayerView() {
    let playerItemBox = document.querySelectorAll(".player-item-box");

    // 将大于该数量的界面，设置为无人游玩（待机界面）
    let player = options.player;
    // 玩家有1个，2,3,4界面为待机-> 对应索引是1,2,3
    // 玩家有2个，3,4界面为待机-> 对应索引是2,3
    // 玩家有3个，4界面为待机-> 对应索引是3
    for (let i = 0; i < playerItemBox.length; i++) {
        // 有玩家
        if (i < player) {
            let div = createPlayerView();
            playerItemBox[i].appendChild(div);

            // 一开始写错了，push给数组末尾添加元素
            playerDivs.push(div);
            // 玩家数据信息
            players.push({
                // 当前所有金额
                points: options.points,
                // 赢的次数
                win: 0,
                // 输的次数
                lose: 0,
                // 当前押注金额
                bet: 0,
                // 当前牌组
                cards: [],
                // 是否爆掉
                isBoom: false,
                // 是否游戏结束
                isGameover: false,
            });

            updatePlayerInfoView(i);

            // 无玩家
        } else {
            playerItemBox[i].appendChild(createNoPlayerView());
        }

    }
    // 进入下一个游戏环节
    nextProcedure();

}

// 创建无人游玩的模板
function createNoPlayerView() {
    // 获取无人游玩的模板
    let div = document.querySelector("#templates>.without-player-box");
    console.log("div = ", div);

    // 克隆
    return div.cloneNode(true);
}

// 创建有玩家游玩的模板
function createPlayerView() {
    // 获取玩家的模板
    let div = document.querySelector("#templates>.with-player-box");
    console.log("div = ", div);

    // 克隆
    return div.cloneNode(true);
}

/**
 * 设置当前操作玩家的索引
 * @param {number} index 
 */
function setPlayerIndex(index) {
    // 如果当前玩家game over那么进入下一个玩家
    if (players[index] && players[index].isGameover) {
        // 递归调用
        setPlayerIndex(index + 1);
        return;
    }
    playerIndex = index;
    // 遍历玩家div
    for (let i in playerDivs) {
        // 当前玩家展示出按钮
        if (i == index) {
            playerDivs[i].querySelector(".procedure-view-box").classList.remove("hidden-player");
            // 其余玩家隐藏按钮
        } else {
            playerDivs[i].querySelector(".procedure-view-box").classList.add("hidden-player");
        }
    }
}

/**
 * 第一个游戏环节：切牌操作
 * @param {boolean} flag 是否切牌
 */
function handleCut(flag) {
    // 不切牌
    if (!flag) {
        setPlayerIndex(playerIndex + 1);
        // 切牌
    } else {
        // 弹出交互框，获取用户输入的字符串值
        while (true) {
            let value = prompt("请问要从第几张牌来切（2-52）");
            if (value) {
                let number = parseInt(value);
                // 严谨性判断
                if (number != NaN && number >= 2 && number <= 52) {
                    // 计算机索引从0开始，而人一般计数从1开始，所以减去1
                    cutCards(number - 1);
                    setPlayerIndex(playerIndex + 1);
                    break;
                }
            }
        }
    }

    // 如果所有玩家操作完毕，进入下一个游戏环节
    if (playerIndex == playerDivs.length) {
        alert("切牌完毕，进入押注环节");
        nextProcedure();
    }
}

/**
 * 进入下一个游戏环节
 * 让游戏界面只显示当前游戏环节的界面
 */
function nextProcedure() {
    setPlayerIndex(0);
    procedureIndex++;
    // 如果游戏环节结束，又回到第一个游戏环节
    if (procedureIndex >= procedure.length) {
        procedureIndex = 0;
    }
    // 进入下一个环节，让玩家1先操作
    console.log("进入下一个游戏环节：", procedure[procedureIndex], "procedureIndex = ", procedureIndex)
        // 遍历玩家界面，与当前游戏环节不同的游戏环节界面关闭
    for (let v of playerDivs) {
        // 找到所有游戏环节盒子
        let boxes = v.querySelectorAll(".procedure-box");
        // console.log("v = ",v);
        // console.log("boxes.length = ",boxes.length);
        // 以索引方式循环，不能使用for...in循环，boxes是伪数组，会随机出其它key
        for (let i = 0; i < boxes.length; i++) {
            // console.log("boxes[i] = ",boxes[i]);
            if (i == procedureIndex) {
                // classList: 获取dom对象的class操作对象
                boxes[i].classList.remove("need-hidden");
                console.log("i = ", i)
                console.log(boxes[i].className);
            } else {
                boxes[i].classList.add("need-hidden");
            }
        }
    }
}

/**
 * 滑动押注金额条时，修改显示的数据
 */
function handleBetChange(input) {
    let value = input.value;
    // 通过当前玩家，在玩家面板中查找到span
    playerDivs[playerIndex].querySelector(".bet-show-points").innerText = value;
}

/**
 * 押注
 */
function handleBet() {
    let value = playerDivs[playerIndex].querySelector(".bet-input").value;
    players[playerIndex].points -= value;
    players[playerIndex].bet = value;
    updatePlayerInfoView(playerIndex);
    setPlayerIndex(playerIndex + 1);
    // 如果所有玩家操作完毕，进入发牌游戏环节
    if (playerIndex == playerDivs.length) {
        alert("押注完毕，进入发牌环节");
        dealCards();
    }
}

/**
 * 
 * 更新当前玩家的信息
 */
function updatePlayerInfoView(idx) {
    let spans = playerDivs[idx].querySelectorAll(".span-display");
    // 更改显示信息
    spans[0].innerText = players[idx].points;
    spans[1].innerText = players[idx].bet;
    spans[2].innerText = players[idx].win;
    spans[3].innerText = players[idx].lose;

    // 根据当前金额更新押注滑动条的可使用范围
    let betInput = playerDivs[idx].querySelector(".bet-input");
    betInput.value = 100;
    betInput.max = players[idx].points >= 300 ? 300 : players[idx].points;

    playerDivs[idx].querySelector(".bet-show-points").innerText = 100;
}

/**
 * 更新庄家信息
 * @param {boolean} hiddenCard 是否隐藏一张牌
 */
function updateBankerInfoView(hiddenCard) {
    let spans = bankerBox.querySelectorAll(".span-display");
    console.log(banker);
    // 庄家的信息显示
    spans[0].innerText = banker.win;
    spans[1].innerText = banker.lose;

    let span = bankerBox.querySelector(".display-points");
    span.innerText = getCardsPointsInfo(banker.cards);

    getCardsView(banker.cards);

    /**
     * 更新牌组展示
     * @param {Array} cards 
     */
    function getCardsView(cards) {
        let parent = bankerBox.querySelector(".display-cards");
        // 清空内容
        parent.innerText = "";
        for (let i = 0; i < cards.length; i++) {
            let li = document.createElement("li");
            li.classList.add("card-div");
            // 隐藏第一张牌
            if (i == 0 && hiddenCard) {
                li.style.backgroundColor = '#000';
            } else {
                li.innerText = cards[i].suit + " " + cards[i].point;
            }
            // 添加子元素
            parent.appendChild(li);
        }
    }

    /**
     * 获取庄家的点数显示
     */
    function getCardsPointsInfo(cards) {
        // 如果隐藏，那么跳过第一张牌计算
        let i = hiddenCard ? 1 : 0;
        let sum = 0;
        for (; i < cards.length; i++) {
            let point = cards[i].point >= 11 ? 10 : cards[i].point;
            sum += point;
        }
        return hiddenCard ? '? + ' + sum : sum;
    }
}

/**
 * 更新玩家牌的显示情况
 * @param {number} idx 
 */
function updatePlayerCardsView(idx) {
    console.log("players[idx].cards = ", players[idx].cards);

    let span = playerDivs[idx].querySelector(".display-points");
    span.innerText = getCardsPoints(players[idx].cards);

    let ul = playerDivs[idx].querySelector(".display-cards");
    getCardsView(ul, players[idx].cards);

    /**
     * 更新牌组展示
     * @param {DOM} parent 
     * @param {Array} cards 
     */
    function getCardsView(parent, cards) {
        // 清空内容
        parent.innerText = "";
        for (let v of cards) {
            let li = document.createElement("li");
            li.classList.add("card-div");
            li.innerText = v.suit + " " + v.point;
            // 添加子元素
            parent.appendChild(li);
        }
    }
}

/**
 * 传入牌组，求出点数
 * @param {Array} cards 
 */
function getCardsPoints(cards) {
    let sum = 0;
    for (let v of cards) {
        let point = v.point >= 11 ? 10 : v.point;
        sum += point;
    }
    return sum;
}



/**
 * 首轮发牌
 * 从牌组中轮流发牌
 */
function dealCards() {
    // 清空庄家牌组（避免上一局的牌影响）
    banker.cards = [];
    // 清空玩家牌组
    for (let i = 0; i < players.length; i++) {
        players[i].cards = [];
    }

    // 发两轮，每次一张牌
    for (let i = 0; i < 2; i++) {
        let card = cards.shift();
        banker.cards.push(card);

        for (let j = 0; j < players.length; j++) {
            card = cards.shift();
            players[j].cards.push(card);
            if (i == 1) {
                // 发完两张牌，直接更新点数和牌组显示
                updatePlayerCardsView(j);
            }
        }
    }
    // 更新庄家显示信息
    updateBankerInfoView(true);
    // alert("发牌完毕，进入要牌环节");
    // 进入下一个游戏环节
    nextProcedure();
}

/**
 * 要牌：从牌组内抽取一张牌
 * @param {boolean} flag 是否要牌
 */
function handleRequest(flag) {
    if (flag) {
        // 抽取第一张牌
        let card = cards.shift();
        alert("抽取成功");
        players[playerIndex].cards.push(card);
        updatePlayerCardsView(playerIndex);

        let points = getCardsPoints(players[playerIndex].cards);
        // 判断是否爆掉
        if (points > 21) {
            alert("你爆掉了！")
            boom(playerDivs[playerIndex], players[playerIndex]);
            // 进入下一个玩家
            setPlayerIndex(playerIndex + 1);
            // 所有玩家要牌完毕，进入庄家要牌环节
            if (playerIndex == playerDivs.length) {
                bankerRequest();
            }
        }
    } else {
        // 进入下一个玩家
        setPlayerIndex(playerIndex + 1)

        // 所有玩家要牌完毕，进入庄家要牌环节
        if (playerIndex == playerDivs.length) {
            bankerRequest();
        }
    }
}

/**
 * 处理爆掉结果
 * @param {DOMObject} parentDom 父节点
 * @param {Object} obj 玩家
 */
function boom(parentDom, obj) {
    parentDom.querySelector(".procedure-view-box").classList.add("need-hidden");
    parentDom.querySelector(".boom-view-box").classList.remove("need-hidden");
    obj.isBoom = true;
}

/**
 * 庄家要牌环节
 */
function bankerRequest() {
    // 先展示专家的所有底牌
    updateBankerInfoView(false);

    // 判断玩家是否全部爆掉
    let flag = players.every(v => v.isBoom);
    if (flag) {
        alert("所有玩家都爆掉。");
        accounts();
        return;
    }
    alert("所有玩家要牌完毕，进入庄家要牌环节。");

    // 循环
    while (true) {
        let points = getCardsPoints(banker.cards);
        // 小于16时必定要牌
        if (points < 16) {
            alert("庄家要了一张牌");
            let card = cards.shift();
            banker.cards.push(card);
            points = getCardsPoints(banker.cards);
            updateBankerInfoView(false);
            if (points > 21) {
                banker.isBoom = true;
                break;
            }
            // 21点：不要牌
        } else if (points == 21) {
            break;
        } else {
            let r = getRandom(100);
            // 随机，50%几率要牌
            if (r >= 50) {
                alert("庄家要了一张牌");
                let card = cards.shift();
                banker.cards.push(card);
                points = getCardsPoints(banker.cards);
                updateBankerInfoView(false);
                if (points > 21) {
                    banker.isBoom = true;
                    break;
                }
            }
        }
    }
    accounts();
}

/**
 * 结算
 */
function accounts() {
    // let flag = true;
    // // 判断玩家是否全部爆掉
    // for (let v of players) {
    //     if (!v.isBoom) {
    //         flag = false;
    //         break;
    //     }
    // }
    // 以上是传统的for循环写法

    // 判断玩家是否全部爆掉
    let flag = players.every(v => v.isBoom);
    if (flag) {
        for (let i in players) {
            players[i].lose++;
            banker.win++;
            updatePlayerInfoView(i);

        }
        updateBankerInfoView();
        isGameover();
        return;
    }

    // 庄家爆掉，没有爆掉的玩家胜利
    if (banker.isBoom) {
        for (let i in players) {
            console.log("i =", i);
            // 玩家没有爆掉
            if (!players.isBoom) {
                // 因为押注的时候扣了金额，所以这里加的金额*2
                players[i].points += players[i].bet * 2;
                players[i].win++;

                banker.lose++;

                // 玩家爆掉
            } else {

                players[i].lose++;

                banker.win++;
            }
            updatePlayerInfoView(i);
        }
        // 庄家没有爆掉，那么玩家必须比庄家的分高
    } else {
        let bankerPoints = getCardsPoints(banker.cards);
        for (let i in players) {
            let playerPoints = getCardsPoints(players[i].cards);
            if (playerPoints > bankerPoints) {
                players[i].points += players[i].bet * 2;
                players[i].win++;
                banker.lose++;
            } else {
                players[i].lose++;
                banker.win++;
            }
            updatePlayerInfoView(i);
        }
    }
    updateBankerInfoView();
    isGameover();
}

/**
 * 判断玩家是否game over
 */
function isGameover() {
    let allGameover = true;
    for (let i in players) {
        // 金额为0，那么gameover
        if (players[i].points == 0) {
            players[i].isGameover = true;
            playerDivs[i].querySelector(".procedure-view-box").classList.addClass("need-hidden");
            let div = playerDivs[i].querySelector(".boom-view-box");
            div.classList.removeClass("need-hidden");
            div.querySelector("h3").innerText = "Game Over";
        } else {
            allGameover = false;
        }
    }

    // 如果所有玩家gameover那么游戏结束
    if (allGameover) {
        alert("游戏结束");
        // 进入下一轮
    } else {
        alert("进入新一轮游戏");
        initCards();
        for (let i in players) {
            players[i].isBoom = false;
            players[i].bet = 0;
            // 没有gameover的玩家隐藏爆掉界面，显示游戏界面
            if (!players[i].isGameover) {
                playerDivs[i].querySelector(".boom-view-box").classList.add("need-hidden");
                playerDivs[i].querySelector(".procedure-view-box").classList.remove("need-hidden");
            }
            updatePlayerInfoView(i);
        }
        nextProcedure();
    }
}